/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.list.tree;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.*;
import cn.easyplatform.messages.response.ListPagingResponseMessage;
import cn.easyplatform.messages.response.ListQueryResponseMessage;
import cn.easyplatform.messages.response.PageResponseMessage;
import cn.easyplatform.messages.vos.FieldUpdateVo;
import cn.easyplatform.messages.vos.PageVo;
import cn.easyplatform.messages.vos.datalist.*;
import cn.easyplatform.spi.service.ComponentService;
import cn.easyplatform.spi.service.ListService;
import cn.easyplatform.type.Constants;
import cn.easyplatform.type.DeviceType;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.ext.Destroyable;
import cn.easyplatform.web.ext.zul.Datalist;
import cn.easyplatform.web.layout.IMainTaskBuilder;
import cn.easyplatform.web.layout.LayoutManagerFactory;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.BackendException;
import cn.easyplatform.web.task.MainTaskSupport;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.event.EventEntry;
import cn.easyplatform.web.task.event.FieldEntry;
import cn.easyplatform.web.task.support.ManagedComponent;
import cn.easyplatform.web.task.zkex.DropSupport;
import cn.easyplatform.web.task.zkex.list.OperableListSupport;
import cn.easyplatform.web.task.zkex.list.menu.SimpleColumnMenu;
import cn.easyplatform.web.task.zkex.listener.DropEventListener;
import cn.easyplatform.web.task.zkex.listener.SelectedEventListener;
import cn.easyplatform.web.utils.PageUtils;
import cn.easyplatform.web.utils.WebUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlBasedComponent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.*;
import org.zkoss.zul.impl.InputElement;

import java.util.*;
import java.util.Map.Entry;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public abstract class AbstractOperableTreeBuilder extends AbstractTreeBuilder
        implements OperableListSupport, DropSupport, Destroyable {

    protected List<String> editableFields;

    protected List<String> children;

    protected Object[] currentFromKeys;

    private String processCode;

    //后台服务发送过来的刷新事件
    private EventListener<Event> el;

    AbstractOperableTreeBuilder(OperableHandler mainTaskHandler, Datalist dl, Component anchor) {
        super(mainTaskHandler, dl, anchor);
        children = new ArrayList<String>();
    }

    @Override
    public Component build() {
        if (!Strings.isBlank(getEntity().getHost())) {
            if (getEntity().getType().equals(Constants.CATALOG))
                throw new EasyPlatformWithLabelKeyException(
                        "datalist.detail.not.suppor", listExt.getId());
            getEntity().setShowPanel(false);
            getEntity().setImmediate(false);
            Collection<ManagedComponent> list = ((MainTaskSupport) mainTaskHandler)
                    .getManagedEntityComponents();
            for (ManagedComponent es : list) {
                if (es instanceof OperableListSupport) {
                    OperableListSupport os = (OperableListSupport) es;
                    if (os.getComponent().getId().equals(getEntity().getHost()))
                        os.addChild(listExt.getId());
                }
            }
        }
        if (!Strings.isBlank(getEntity().getEditableColumns())) {
            editableFields = new ArrayList<String>();
            String[] fields = getEntity().getEditableColumns().split("\\,");
            for (String f : fields) {
                f = f.trim();
                if (f.equals(""))
                    continue;
                editableFields.add(f);
            }
        }
        if (getEntity().isCheckmark())
            listExt.addEventListener(Events.ON_SELECT,
                    new SelectedEventListener(this));
        if (listExt.getDroppable() != null
                && listExt.getDroppable().equalsIgnoreCase("true")) // 可以拖放
            listExt.addEventListener(Events.ON_DROP,
                    new DropEventListener(this));
        processCode = "R";
        return super.build();
    }

    @Override
    public void destory() {
        if (el != null)
            Contexts.unsubscribe(Constants.EASYPLATFORM_TOPIC, el);
    }

    @Override
    public void copy(EventEntry<String> entry) {
        if (isCustom())
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.invalid.action", getName());
        ListRowVo rv = getSelectedValue();
        if (rv == null)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.selected.empty", getName());
        this.processCode = "C";
        if (isEditable()) {
            ListService dls = ServiceLocator
                    .lookup(ListService.class);
            ListCreateVo cv = new ListCreateVo(listExt.getId());
            if (!Strings.isBlank(getEntity().getHost()))
                cv.setFromKeys(getFromKeys());
            cv.setCopyKeys(rv.getKeys());
            IResponseMessage<?> resp = dls
                    .doCreate(new ListCreateRequestMessage(getId(), cv));
            if (resp.isSuccess())
                setRowInfo(createRow((ListRowVo) resp.getBody()));
            else
                throw new BackendException(resp);
        } else
            open("C", entry, rv.getKeys());
    }

    private void setRowInfo(Treeitem li) {
        if (clickType > 0) {
            li.setEvent(listExt.getEvent());
            addEventListener(li, clickType == 1 ? Events.ON_CLICK
                    : Events.ON_DOUBLE_CLICK);
        }
        if (paging != null)//移动到最后一页
            paging.setActivePage(paging.getPageCount() - 1);
        Iterator<Component> itr = li.queryAll("treecell").iterator();
        while (itr.hasNext()) {
            Component c = itr.next();
            if (c.getFirstChild() instanceof InputElement) {
                ((InputElement) c.getFirstChild()).focus();
                //Clients.evalJavaScript("zk.$('" + c.getFirstChild().getUuid() + "').focus(0)");
                break;
            }
        }
    }

    @Override
    public void create(EventEntry<String> entry) {
        if (isCustom())
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.invalid.action", getName());
        this.processCode = "C";
        if (isEditable()) {
            ListService dls = ServiceLocator
                    .lookup(ListService.class);
            ListCreateVo cv = new ListCreateVo(listExt.getId());
            if (!Strings.isBlank(getEntity().getHost()))
                cv.setFromKeys(getFromKeys());
            IResponseMessage<?> resp = dls
                    .doCreate(new ListCreateRequestMessage(getId(), cv));
            if (resp.isSuccess())
                setRowInfo(createRow((ListRowVo) resp.getBody()));
            else
                throw new BackendException(resp);
        } else
            open("C", entry, null);
    }

    @Override
    public void delete(EventEntry<String> entry) {
        if (isCustom())
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.invalid.action", getName());
        if (listExt.getSelectedCount() == 0) {
            if (getSelectedValue() == null)
                throw new EasyPlatformWithLabelKeyException(
                        "datalist.selected.empty", getName());
        }
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        ListSelectetRowsVo srv = new ListSelectetRowsVo(listExt.getId());
        for (Treeitem li : listExt.getSelectedItems()) {
            ListRowVo rv = li.getValue();
            if (rv != null)
                srv.appendKey(rv.getKeys());
        }
        if (srv.getKeyList().isEmpty())
            return;
        IResponseMessage<?> resp = dls.doDelete(new ListDeleteRequestMessage(
                getId(), srv));
        if (resp.isSuccess()) {
            int size = listExt.getSelectedCount();
            List<Treeitem> deletedItems = new ArrayList<Treeitem>();
            for (Treeitem li : listExt.getSelectedItems()) {
                Object[] keys = ((ListRowVo) li.getValue()).getKeys();
                for (String child : children) {
                    for (ManagedComponent es : ((MainTaskSupport) getParent())
                            .getManagedEntityComponents()) {
                        if (es instanceof OperableListSupport) {
                            OperableListSupport os = (OperableListSupport) es;
                            if (os.getComponent().getId().equals(child)
                                    && Lang.equals(keys,
                                    os.getCurrentFromKeys())) {
                                os.clear();
                                clear(os);
                            }
                        }
                    }
                }
                deletedItems.add(li);
            }
            for (Treeitem item : deletedItems) {
                item.detach();
                item = null;
            }
            deletedItems = null;
            if (paging != null
                    && getEntity().getType().equals(Constants.CATALOG))
                paging.setTotalSize(paging.getTotalSize() - size);
        } else
            throw new BackendException(resp);
    }

    @Override
    public void edit(EventEntry<String> entry) {
        if (isCustom())
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.invalid.action", getName());
        if (listExt.getSelectedCount() == 0)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.selected.empty", getName());
        this.processCode = "U";
        open("U", entry, null);
    }

    @Override
    public void read(EventEntry<String> entry) {
        if (listExt.getSelectedCount() == 0)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.selected.empty", getName());
        this.processCode = "R";
        open("R", entry, null);
    }

    protected void open(String code, EventEntry<String> entry, Object[] copyKeys) {
        ListRowVo rv = getSelectedValue();
        if (rv == null && !"C".equals(code))// is group
            return;
//        if (copyKeys == null && listExt.getSelectedItem() != null) {
//            rv = listExt.getSelectedItem().getValue();
//            if (rv == null)// is group
//                return;
//        }
        if (Strings.isBlank(getEntity().getPageId())) {
            if (getEntity().getType().equals(Constants.CATALOG)
                    && getEntity().isDurable()) {// 作为清单使用
                ListService dls = ServiceLocator
                        .lookup(ListService.class);
                ListSelectedRowVo srv = new ListSelectedRowVo(listExt.getId(),
                        rv.getKeys());
                srv.setCode(code);
                IResponseMessage<?> resp = dls
                        .doSelect(new ListSelectRequestMessage(mainTaskHandler
                                .getId(), srv));
                if (!resp.isSuccess())
                    throw new BackendException(resp);
                mainTaskHandler.setProcessCode(code);
                mainTaskHandler.reload(new String[0]);
            } else
                throw new EasyPlatformWithLabelKeyException(
                        "component.property.not.found", listExt.getId(),
                        "pageId");
        } else {
            if (getEntity().getOpenModel() == Constants.OPEN_EMBBED
                    && Strings.isBlank(getEntity().getContainer()))
                throw new EasyPlatformWithLabelKeyException(
                        "component.property.not.found", listExt.getId(),
                        "container");
            ListOpenVo lpv = new ListOpenVo();
            lpv.setId(listExt.getId());
            lpv.setOpenModel(getEntity().getOpenModel());
            lpv.setPageId(getEntity().getPageId());
            lpv.setProcessCode(code);
            lpv.setCopyKeys(copyKeys);
            if (!code.equals("C")) {
                lpv.setKeys(rv.getKeys());
            } else if (!Strings.isBlank(getEntity().getHost()))
                lpv.setKeys(getFromKeys());
            ListService dls = ServiceLocator
                    .lookup(ListService.class);
            ListOpenRequestMessage req = new ListOpenRequestMessage(lpv);
            if (entry.getActionFlag() != 0) {
                req.setActionFlag(entry.getActionFlag());
                req.setId(entry.getEntry());
            } else
                req.setId(getId());
            IResponseMessage<?> resp = dls.doOpen(req);
            if (!resp.isSuccess())
                throw new BackendException(resp);
            if (resp instanceof PageResponseMessage) {
                PageVo pv = ((PageResponseMessage) resp).getBody();
                Component container = null;
                if (getEntity().getOpenModel() == Constants.OPEN_EMBBED) {
                    container = mainTaskHandler.getComponent().getFellowIfAny(
                            getEntity().getContainer());
                    if (container == null)
                        pv.setOpenModel(Constants.OPEN_MODAL);
                }
                if (container == null) {
                    container = mainTaskHandler.getComponent().getPage()
                            .getFellowIfAny("gv5container");
                    if (container == null) {
                        container = mainTaskHandler.getContainer();
                        pv.setOpenModel(Constants.OPEN_MODAL);
                    }
                }
                MainTaskSupport builder = null;
                try {
                    builder = (MainTaskSupport) LayoutManagerFactory
                            .createLayoutManager()
                            .getMainTaskBuilder(container,
                                    pv.getId(), pv);
                    ((IMainTaskBuilder) builder).build();
                    ((IMainTaskBuilder) builder).setHost(this);
                } catch (EasyPlatformWithLabelKeyException ex) {
                    builder.close(false);
                    throw ex;
                } catch (BackendException ex) {
                    builder.close(false);
                    throw ex;
                } catch (Exception ex) {
                    builder.close(false);
                    throw Lang.wrapThrow(ex);
                }
            }
        }
    }

    @Override
    public void update(ListUpdatableRowVo lor) {
        if (lor.isCreate()) {
            Treeitem li = createRow(lor);
            if (clickType > 0) {
                li.setEvent(listExt.getEvent());
                addEventListener(li, clickType == 1 ? Events.ON_CLICK
                        : Events.ON_DOUBLE_CLICK);
            }
            Clients.scrollIntoView(li);
        } else {
            Treeitem item = getRowByKey(lor.getKeys());
            if (item != null) {
                if (!item.isSelected())
                    item.setSelected(lor.isSelected());
                item.setVisible(true);
                updateRow(item, lor.getData(), false);
                Clients.scrollIntoView(item);
            }
        }
    }

    @Override
    public void save(EventEntry<Boolean> entry) {
        // if (isCustom())
        // throw new EasyPlatformWithLabelKeyException(
        // "datalist.invalid.action", getName());
        ListSaveVo sv = null;
        if (entry.getEntry()) {// commit提交列表
            sv = new ListSaveVo(listExt.getId());
        } else {// save提交所选的记录
            if (WebUtils.isCellEvent()) {
                if (listExt.getSelectedCount() > 0) {
                    ListRowVo rv = WebUtils.getItemData(this, listExt.getSelectedItem());
                    sv = new ListSaveVo(listExt.getId(), rv.getKeys(), rv.getData());
                } else
                    throw new EasyPlatformWithLabelKeyException(
                            "datalist.selected.empty", getName());
            } else
                sv = new ListSaveVo(listExt.getId());
        }
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        IResponseMessage<?> resp = dls.doSave(new ListSaveRequestMessage(
                getId(), sv));
        if (!resp.isSuccess())
            throw new BackendException(resp);
        this.processCode = "R";
    }

    @Override
    public void refresh(EventEntry<FieldEntry> entry) {
        ListRowVo rv = null;
        if (listExt.getSelectedItem() != null)
            rv = listExt.getSelectedItem().getValue();
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        IResponseMessage<?> resp = dls.doRefresh(new ListRefreshRequestMessage(
                getId(), new ListRefreshVo(listExt.getId(), entry.getEntry()
                .getFields(), rv == null ? null : rv.getKeys())));
        if (resp.isSuccess()) {
            if (resp instanceof ListPagingResponseMessage) {
                List<ListRowVo> rs = ((ListPagingResponseMessage) resp)
                        .getBody();
                clear();
                redraw(rs);
            } else {
                Object[] data = (Object[]) resp.getBody();
                String[] fields = entry.getEntry().getFields();
                if (fields != null && fields.length > 0
                        && !fields[0].equals("*")) {
                    Object[] odata = rv.getData();
                    int size = layout.getHeaders().size();
                    for (int i = 0; i < fields.length; i++) {
                        for (int j = 0; j < size; j++) {
                            ListHeaderVo hv = layout.getHeaders().get(j);
                            if (hv.getName().equals(fields[i])) {
                                odata[getEntity().isShowRowNumbers() ? j - 1 : j] = data[getEntity().isShowRowNumbers() ? j - 1 : j];
                                break;
                            }
                        }
                    }
                    data = odata;
                }
                rv.setData(data);
                updateRow(listExt.getSelectedItem(), data, entry.getEntry()
                        .isSendEvent());
            }
        } else
            throw new BackendException(resp);
    }

    private void updateRow(Treeitem ti, Object[] data, boolean isSendEvent) {
        try {
            if (expressionEngine != null)
                expressionEngine.compile();
            Treerow li = (Treerow) ti.getFirstChild();
            Map<String, Object> evalMap = new HashMap<String, Object>();
            Map<String, Component> managedComponents = new HashMap<String, Component>();
            for (int i = 0; i < data.length; i++) {
                ListHeaderVo hv = null;
                Component c = null;
                if (getEntity().isShowRowNumbers()) {
                    c = li.getChildren().get(i + 1);
                    hv = layout.getHeaders().get(i + 1);
                } else {
                    c = li.getChildren().get(i);
                    hv = layout.getHeaders().get(i);
                }
                if (c.getFirstChild() != null)
                    c = c.getFirstChild();
                if (hv.isEditable()) {
                    Object value = PageUtils.getValue(c, false);
                    if (!Lang.equals(value, data[i])) {
                        PageUtils.setValue(c, data[i]);
                        if (isSendEvent && !Strings.isBlank(c.getEvent())) {
                            Event evt = new Event(Events.ON_CHANGE, c);
                            Events.sendEvent(c, evt);
                        }
                    }
                } else if (!(c instanceof Button) && !(c instanceof A)) {
                    Object value = data[i];
                    if (!Strings.isBlank(hv.getFormat()) && value != null)
                        value = WebUtils.format(hv.getFormat(), data[i]);
                    PageUtils.setValue(c, value);
                }
                if (hv.isTotal() && data[i] != null)
                    hv.caculate(data[i].toString(), true);
                evalMap.put(hv.getName(), data[i]);
                managedComponents.put(hv.getName(), c);
            }
            if (expressionEngine != null)
                expressionEngine.eval(ti, evalMap, managedComponents);
            evalMap = null;
        } finally {
            if (expressionEngine != null)
                expressionEngine.destroy();
        }
    }

    @Override
    public void reset(boolean clearAll) {
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        ListResetVo vo = new ListResetVo(listExt.getId());
        if (!clearAll) {
            if (!Strings.isBlank(getEntity().getHost()))
                vo.setFromKeys(getFromKeys());
        }
        IResponseMessage<?> resp = dls.doReset(new ListResetRequestMessage(
                getId(), vo));
        if (resp.isSuccess())
            clear();
        else
            throw new BackendException(resp);
    }

    @Override
    public void reload(String... comps) {
        this.processCode = "R";
        // 重新加载列表数据
        Object[] keys = null;
        if (!Strings.isBlank(getEntity().getHost()))
            keys = getFromKeys();
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        IResponseMessage<?> resp = dls.doReload(new ListReloadRequestMessage(
                getId(), new ListReloadVo(listExt.getId(), keys,
                comps.length > 0 && comps[0].equals("*"))));
        if (resp.isSuccess()) {
            if (useHeaderVariable)
                createHeader();
            ListQueryResultVo rv = ((ListQueryResponseMessage) resp).getBody();
            if (rv.getData() == null || rv.getData().isEmpty())
                setPagingInfo(0, 0);
            else
                setPagingInfo(rv.getTotalSize(), 0);
            clear();
            if (rv.getErrMsg() != null)
                setEmptyMessage(rv.getErrMsg());
            else {
                redraw(rv.getData());
                refreshFoot();
            }
            currentFromKeys = keys;
        } else
            throw new BackendException(resp);
    }

    @Override
    public void update(String... comps) {
        if (log.isDebugEnabled())
            log.debug("update->{}", Lang.concat(comps));
        if (comps.length == 0)
            return;
        ListRowVo rv = getSelectedValue();
        ListFieldUpdateVo lfus = new ListFieldUpdateVo(listExt.getId(),
                layout.isCustom() ? rv.getData() : rv.getKeys());
        Set<Entry<String, Component>> set = getManagedComponents().entrySet();
        for (Entry<String, Component> entry : set) {
            Component comp = entry.getValue();
            if (!(comp instanceof Treecell)) {
                if (comps[0].equals("*")) {
                    lfus.addField(new FieldUpdateVo(entry.getKey(), PageUtils
                            .getValue(comp, false)));
                } else {
                    for (int i = 0; i < comps.length; i++) {
                        if (entry.getKey().equals(comps[i])) {
                            lfus.addField(new FieldUpdateVo(comps[i], PageUtils
                                    .getValue(comp, false)));
                            break;
                        }
                    }
                }
            }
        }
        SimpleRequestMessage req = new SimpleRequestMessage(getId(), lfus);
        IResponseMessage<?> resp = ServiceLocator.lookup(
                ComponentService.class).fieldUpdate(req);
        if (!resp.isSuccess())
            throw new BackendException(resp);
    }

    private Object[] getFromKeys() {
        Object[] keys = null;
        for (ManagedComponent es : ((MainTaskSupport) getParent())
                .getManagedEntityComponents()) {
            if (es instanceof OperableListSupport) {
                OperableListSupport os = (OperableListSupport) es;
                if (os.getComponent().getId().equals(getEntity().getHost())) {
                    if (os.getComponent() instanceof Listbox) {
                        Listbox dl = (Listbox) os.getComponent();
                        if (dl.getSelectedCount() == 0)
                            throw new EasyPlatformWithLabelKeyException(
                                    "datalist.from.selected.empty", getName());
                        keys = ((ListRowVo) dl.getSelectedItem().getValue())
                                .getKeys();
                        break;
                    } else {
                        Tree dl = (Tree) os.getComponent();
                        if (dl.getSelectedCount() == 0)
                            throw new EasyPlatformWithLabelKeyException(
                                    "datalist.from.selected.empty", getName());
                        keys = ((ListRowVo) dl.getSelectedItem().getValue())
                                .getKeys();
                        break;
                    }
                }
            }
        }
        if (keys == null)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.from.not.found", getEntity().getHost());
        return keys;
    }

    private void clear(OperableListSupport parent) {
        for (String child : parent.getChildren()) {
            for (ManagedComponent es : ((MainTaskSupport) getParent())
                    .getManagedEntityComponents()) {
                if (es instanceof OperableListSupport) {
                    OperableListSupport os = (OperableListSupport) es;
                    if (os.getComponent().getId().equals(child)) {
                        os.clear();
                        clear(os);
                    }
                }
            }
        }
    }

    @Override
    public void drop(ListDropVo vo) {
        if (!Strings.isBlank(getEntity().getHost())) {
            try {
                vo.setKey(getFromKeys());
            } catch (EasyPlatformWithLabelKeyException ex) {
                MessageBox.showMessage(ex);
                return;
            }
        }
        vo.setTargetId(listExt.getId());
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        IResponseMessage<?> resp = dls.doDrop(new DropRequestMessage(getId(),
                vo));
        if (resp.isSuccess()) {
            List<?> data = (List<?>) resp.getBody();
            for (Object row : data)
                update((ListUpdatableRowVo) row);
        } else
            MessageBox.showMessage(resp);
    }

    @Override
    protected void setMenupopup(HtmlBasedComponent head) {
        if (Contexts.getEnv().getDeviceType().equalsIgnoreCase(DeviceType.AJAX.getName())) {
            Menupopup popup = new SimpleColumnMenu(head, this, getEntity()
                    .isExport(), getEntity().isPrint());
            popup.setId(listExt.getId() + "_popup");
            // Borderlayout
            Component layout = listExt.getParent().getParent();
            West west = new West();
            west.setBorder("none");
            west.setSize("0");
            west.setCollapsible(false);
            layout.appendChild(west);
            west.appendChild(popup);
            List<Treecol> headers = head.getChildren();
            for (Treecol header : headers) {
                A a = new A();
                a.setIconSclass("z-icon-caret-down");
                a.setClass("z-listheader-button");
                a.setHref("javascript:;");
                header.setWidgetListener(Events.ON_MOUSE_OVER,
                        "var $n=jq(this.lastChild.$n());$n.css('display','inline')");
                header.setWidgetListener(Events.ON_MOUSE_OUT,
                        "var $n=jq(this.lastChild.$n());$n.css('display','none')");
                a.setPopup(popup);
                header.appendChild(a);
            }
            head.setAttribute("menupopup", "");
        }
    }

    @Override
    public boolean doItem(Object[] keyValue, int action) {
        Treeitem item = getRowByKey(keyValue);
        if (item != null) {
            if (hasTotal) {
                ListRowVo rv = item.getValue();
                Object[] data = rv.getData();
                for (int i = 0; i < data.length; i++) {
                    ListHeaderVo hv = null;
                    Component c = null;
                    if (getEntity().isShowRowNumbers()) {
                        hv = layout.getHeaders().get(i + 1);
                    } else {
                        hv = layout.getHeaders().get(i);
                    }
                    if (hv.isTotal() && data[i] != null)
                        hv.caculate(data[i].toString(), true);
                }
            }
            //if (action == 0) {
            item.detach();
            item = null;
            //} else
            //    item.setVisible(action == 2);
            return true;
        }
        return false;
    }

    @Override
    public List<Object[]> getKeys(boolean sel) {
        List<Object[]> data = new ArrayList<Object[]>();
        if (sel) {
            if (listExt.getSelectedCount() > 0) {
                for (Treeitem li : listExt.getSelectedItems()) {
                    ListRowVo rv = li.getValue();
                    if (rv != null)
                        data.add(isCustom() ? rv.getData() : rv.getKeys());
                }
            }
        } else {
            for (Treeitem li : listExt.getItems()) {
                ListRowVo rv = li.getValue();
                if (rv != null)
                    data.add(isCustom() ? rv.getData() : rv.getKeys());
            }
        }
        return data;
    }

    @Override
    public boolean setRowVisible(Object[] keyValue, boolean visible) {
        Treeitem item = getRowByKey(keyValue);
        if (item != null) {
            item.setVisible(visible);
            return true;
        }
        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> List<T> getData(boolean sel, boolean orign) {
        List<T> data = new ArrayList<T>();
        if (sel) {
            if (listExt.getSelectedCount() > 0) {
                for (Treeitem li : listExt.getSelectedItems()) {
                    ListRowVo rv = li.getValue();
                    if (rv != null) {
                        T val = (T) (orign ? rv : castTo(rv));
                        data.add(val);
                    }
                }
            }
        } else {
            for (Treeitem li : listExt.getItems()) {
                ListRowVo rv = li.getValue();
                if (rv != null) {
                    T val = (T) (orign ? rv : castTo(rv));
                    data.add(val);
                }
            }
        }
        return data;
    }

    @Override
    public void setPageSize(int pageSize) {
        getEntity().setPageSize(pageSize);
        paging.setPageSize(pageSize);
        paging.setActivePage(0);
    }

    @Override
    public void first() {

    }

    @Override
    public void last() {

    }

    @Override
    public void previous() {

    }

    @Override
    public void next() {

    }

    @Override
    public List<String> getChildren() {
        return children;
    }

    @Override
    public void addChild(String name) {
        children.add(name);
    }

    public Object[] getCurrentFromKeys() {
        return currentFromKeys;
    }

    @Override
    public OperableHandler getParent() {
        return mainTaskHandler;
    }

    @Override
    public String getId() {
        return mainTaskHandler.getId();
    }

    @Override
    public Component getContainer() {
        return mainTaskHandler.getContainer();
    }

    @Override
    public String getTaskId() {
        return mainTaskHandler.getTaskId();
    }

    @Override
    public Map<String, Component> getManagedComponents() {
        Treeitem li = listExt.getSelectedItem();
        if (li != null)
            return WebUtils.getManagedComponents(this, li);
        Event evt = Contexts.getEvent();
        if (evt != null) {
            if (evt.getTarget() instanceof Treeitem) {
                Treeitem sel = (Treeitem) evt.getTarget();
                if (sel.getTree() == listExt) {
                    sel.setSelected(true);
                    return WebUtils.getManagedComponents(this, sel);
                }
            }
            Component parent = evt.getTarget().getParent();
            if (parent != null) {
                int deep = 0;
                while (deep < 6) {
                    if (parent instanceof Treeitem) {
                        Treeitem sel = (Treeitem) parent;
                        if (sel.getTree() == listExt) {
                            sel.setSelected(true);
                            return WebUtils.getManagedComponents(this, sel);
                        } else
                            return null;
                    } else if (parent != null) {
                        parent = parent.getParent();
                        if (parent == null || parent instanceof Tree
                                || parent instanceof Window)
                            break;
                    }
                    deep++;
                }
            }
        }
        return Collections.emptyMap();
    }

    /**
     * @param keyValue
     * @return
     */
    private Treeitem getRowByKey(Object[] keyValue) {
        for (Treeitem item : listExt.getItems()) {
            ListRowVo rv = item.getValue();
            if (rv != null) {
                if (isCustom()) {
                    if (Lang.equals(keyValue, rv.getData())) {
                        return item;
                    }
                } else if (Lang.equals(keyValue, rv.getKeys()))
                    return item;
            }
        }
        return null;
    }

    @Override
    public String getProcessCode() {
        return processCode;
    }

    @Override
    public void setProcessCode(String code) {
        this.processCode = code;
    }

    @Override
    protected void addEventListener(Component comp, String evtName) {
        PageUtils.addEventListener(this, evtName, comp);
    }

    @Override
    public boolean isEditable(String name) {
        if ("*".equals(getEntity().getEditableColumns()))
            return true;
        return editableFields == null ? false : editableFields.contains(name);
    }

    public boolean isEditable() {
        return editableFields == null ? false : !editableFields.isEmpty();
    }

    @Override
    public OperableHandler getMainHandler() {
        return this;
    }

    @Override
    public String[] getAccess() {
        return mainTaskHandler.getAccess();
    }
}
